`timescale 1ns / 1ps
/*
 Copyright 2020 Sean Xiao, jxzsxsp@qq.com
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
 http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

module yue_UART
#(
    parameter PERI_DEEP     = 4,    //memory data width
    parameter PERI_W        = 32,   //memory data width
    parameter PERI_MSK_W    = 4,    //memory data mask width
    parameter PERI_ADDR_W   = 32    //memory address width
)
(
    input  clk,
    
    input  [ PERI_W - 1 : 0 ] i_PERI_din,
    output reg [ PERI_W - 1 : 0 ] o_PERI_dout = 0,
    
    input  [ PERI_ADDR_W - 1 : 0 ] i_addr,
    input  i_cs,
    input  i_we,
    input  [ PERI_MSK_W - 1: 0 ] i_wem,

    output txd_start,
    output [7:0] txd_data,
    input  txd_done,

    input  rst_n
);
//===============================================================================
wire [ PERI_MSK_W - 1: 0 ] wen = ( { PERI_MSK_W{ i_cs & i_we } } & i_wem );
wire ren = i_cs & ( ~i_we );

wire [ 2: 0 ] w_addr = i_addr[ 4: 2 ];


//===============================================================================
wire [ 7: 0 ] UART_VER = 8'h01;
reg  [ 7: 0 ] UART_RUN = 0;
reg  [ 7: 0 ] UART_DATA = 0;
wire [ 7: 0 ] UART_RDY = {7'b000_0000, txd_done};


reg  start_r = 0;
always @( posedge clk )
if(!rst_n) start_r <= 0;
else if( wen[0] & w_addr == 1) start_r <= i_PERI_din[0];
else start_r <= 0;

reg [1:0] start_pos_r = 0;
always @( posedge clk )
if(!rst_n) start_pos_r <= 0;
else start_pos_r <= {start_pos_r[0], start_r};

wire start_pos = (start_pos_r == 2'b01) ? 1'b1 : 1'b0;


always @( posedge clk )
if(!rst_n) UART_RUN <= 0;
else  UART_RUN <= {7'b000_0000, start_pos};


always @( posedge clk )
if(!rst_n) UART_DATA <= 0;
else if( wen[0] & w_addr == 2) UART_DATA <= i_PERI_din[7:0];
//===============================================================================
always @ (*)
begin
    case (w_addr[1:0])
    0: o_PERI_dout = {24'h00_0000, UART_VER};
    1: o_PERI_dout = {24'h00_0000, UART_RUN};
    2: o_PERI_dout = {24'h00_0000, UART_DATA};
    3: o_PERI_dout = {24'h00_0000, UART_RDY};
    endcase
end
//===============================================================================
assign txd_start = start_pos;
assign txd_data = UART_DATA;
//===============================================================================

endmodule
